



#include <iostream>
#include <boost/spirit.hpp>
#include <boost/spirit/include/phoenix.hpp>
using namespace std;
using namespace boost::spirit;
using namespace phoenix;
//closure，为解析器提供存储策略，见例三
struct calc_closure : boost::spirit::closure<calc_closure, double>
{
    member1 val;
};
//四则运算语法类，它也使用了closure的内容策略
struct calculator : public grammar<calculator, calc_closure::context_t>
{
    //语法类重要成员:struct definition
    template <typename ScannerT>
    struct definition
    {
        // factor, term, exp的rule类型，同例三(ScannerT模板在使用时决定)
        typedef rule<phrase_scanner_t, calc_closure::context_t> rule_type;
        rule_type factor, term, exp;
        // 启动rule，在这个例子中，它也是递归的最顶层，负责把exp的最终结果赋值给框架本身。
        rule<phrase_scanner_t> rlStart;
        const rule<phrase_scanner_t>& start() const { return rlStart; }
        //definition的构造函数，self参数引用的是calculator类的实例
        definition(calculator const& self)
        {
            // 四则运算规则定义与例三相同
            factor = real_p[factor.val = arg1] |
                     ('(' >> exp[factor.val = arg1] >> ')');
            term   = factor[term.val = arg1] >>
                                             *(('*' >> factor[term.val *= arg1]) |
                                               ('/' >> factor[term.val /= arg1]));
            exp    = term[exp.val = arg1] >>
                                          *(('+' >> term[exp.val += arg1]) |
                                            ('-' >> term[exp.val -= arg1]));
            //self.val=arg1也是phoenix的匿名函数：把exp的结果赋值给框架本身（self的作用）
            rlStart  = exp[self.val = arg1];
        }
    };
};
int main()
{
    string strVar; //变量名
    double result; //结果
    calculator calc;
    // 赋值语法：变量名 = 表达式
    rule<phrase_scanner_t> rlEqu =  (+alpha_p)[assign(strVar)] >> '=' >> calc[assign_a(result)];
    const char *szEqu = "value = 1 + (2.2 * (3 / (4.8 + 5.5)))";
    parse_info<> r = parse( szEqu , rlEqu, space_p);
    if(r.full) //成功，得到结果
        cout << strVar << " = " << result << endl;
    else  //失败，显示错误位置
        cout << "parase fail !"<<endl << string(r.stop - szEqu, ' ') << '^' << endl;
    return 0;
}



